-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move Metadata Support to Pluginspace #467
Conversation
Python 3.6 has reached its end of life quite a while ago and is thus no longer properly supported by many of our dependencies. CI is also currently broken for python3.6 with the "newer" PyQt5 versions. In the future we need to also add the newer python versions, i.e. 3.9 and 3.10, to our CI pipeline. However, this is not straightforward due to py3exiv2 and will only be done after #467 is merged.
While I won't be able to do a detailed code review quite yet, I do have some initial thoughts (that we probably have shared over mail at some point) and at least CI / dependencies have been fixed in master by now, so a quick rebase would be great 😊 I absolutely love the idea of getting the metadata havoc out of mainline, it has been quite an ordeal, you are right, and thanks again for all your hard work on this! However, I do believe we somehow need to support pyexiv2, given we asked users to switch "recently". Maybe you could just quickly recycle the existing code into another plugin with corresponding name, so we have both in the codebase for now? With this + the rebase, I should absolutely do a full review and we can discuss the details. Later on I can take care of any CI / testing if you like, I feel like this will be messy 😂 but currently all should be fine, as we never test against pyexiv2 (on CI). |
62576fa
to
c9f6d8e
Compare
I have rebased for latest Master. Also, I have rewritten most code, as my initial implementation was a bit limiting, as it allowed only for one metadata handler to be present at the time. The new implementation is a bit more complex in therms of code, but gives more freedom to users, in regards on how they want to handle metadata.
As suggested, I have also created a plugin for metadata support using py3exif2 (which is, however, completely untested (and might even crash) as I am not able to get py3exif2 to run currently). The latest commit is very WIP. I still need to do a lot of cleanup, fix docstrings, fix namings, and minor todos. Also, I have not looked into testing/CI yet (therefore the CI also fails). |
This is golden! I'll only leave a quick overall impression, not any detailed inline comments as of now then. First of all, I absolutely love the flexibility this gives. So following are some random notes, in no particular order:
Random thoughts over :D Once again, love it, and do think the overall structure makes a lot of sense. (Code) details to be checked later 😊 |
Thanks for the high-level feedback. I am glad you like the overall structure. Some comments on your points:
Some additional thoughts:
I will work on it in the following days. Thanks again for your feedback. I wish you a nice weekend! |
Concerning your additional thoughts:
Thanks again for tackling this! And a great week-end to you too! 🥳 |
Thanks for you respond. Concerning 3.:
The way metadata are stored in images is (obviously) standardized (by Exif, IPTC and XMP), however, each package can present the data in whatever way they like. But most fields are basic types anyways. In the worst case a simple regex is probably sufficient to extract the data from the string value, provided by the backend.
If somehow possible, I would like to prevent that any (future) plugin that requires metadata support, has to deal with the backend (piexif, exiv2, py3exiv2, etc.) themselves directly. But I vision that
I hope that clarifies my intend a little. Let me know if this makes sense to you and what you think about it. |
That definitely makes sense, I hope the work that goes into this doesn't get out of hand though 😂 |
ee3613d
to
7a609c7
Compare
Code-vise, this PR is pretty much done; I decided to get rid of the Concerning the MetadataWidget, I do not think that simply by reordering imports we are able to fix the issue. I guess some kind of callback function is needed to set the MetadataWidget as an overlay after the plugins are loaded. But I guess you will come up with a better solution than me, therefore, I will leave this up to you 😊 I am also not sure what information concerning metadata support to return in All tests are currently broken. I will look into them and try to fix them. Did I get it correctly, we get rid of all py3exiv2 related tests? So we only test the no-metadata case and when metadata_piexif is loaded? I will update the docs and the changelog maybe later today or in the next few days. EDIT |
7a609c7
to
232f516
Compare
Thanks again! 😊 This makes perfect sense, the whole PR is complex enough as-is. You are probably right, in some way the metadata widget has to be imported after the plugins, which may mean it is added to the overlays after mw is already created. That is a good question 🤔 Could we add a "name" and "version number" to the metadata plugins somehow, and this is then displayed? Concerning the tests: yes, currently pyexiv2 is not tested, at least not on the CI. I can still run it locally though, since for some reason it still runs fine on my laptop 😄 With the imports, it probably still makes sense to lazy-import piexif / pyexiv2? Not sure about the errors though, will look into that later. I'll try to keep the current momentum up, hopefully at latest next week-end in the train 😊 |
Do you mean name/version of the plugin or of the backend? I have thought about adding the name of the plugin too, but I was not able to come up with a clean solution that enforces clients to set this value. Using some
You mean in the two metadata plugins? Sure, I can do that. Sure, no pressure at all! I find it great that you are able to invest again some time for vimiv! 😃 |
I also had some thoughts on the class that clients can subtype. We would then somehow have to figure out what they implemented, some funky inspection I guess, and add to the implementation registry as is currently the case upon construction of the parent class. I.e. something like (does not work, don't take the names too seriously, just brainstorming): class MetadataPiexif(MetadataBase):
def __init__(self):
super().__init__("piexif", piexif.version)
class MetadataBase:
def __init__(self, name: str, version: str):
self.name = name
self.version = version
# Check what the child implements and update registry
def get_formatted_exif(self):
raise NotImplementedError("Must be implemented by the child class") Could work 🤔 Thanks! Only if this avoids the actual import though 😆 i.e. there is no actual call to piexif.* upon startup. This would probably break at latest if we call |
Yeah, something like this should work. But as you say yourself, we would need to detect what methods get implemented (/overwritten). EDIT Alternatively, something like this could work too:
class Registrar:
def __init__(self, name: str, version: str) -> None:
self._name = name
self._version = version
def register(self, operation: Operations) -> Callable[[customtypes.FuncT], customtypes.FuncT]:
def decorator(func: customtypes.FuncT) -> customtypes.FuncT:
# To something with self._name/self._version here
_registry.register(operation, func)
return func
return decorator
registrar = metadata.Registrar(name="piexif", version=piexif.VERSION)
@registrar.register(metadata.Operations.copy_metadata)
def copy_metadata(path: Path, dest: str, reset_orientation: bool = True) -> bool:
... |
Makes sense, looking at these two options, the baseclass - subtyping approach seems the most clean. Especially with your option of ignoring the |
Doing this, however raises the question on how to implement |
Yep, you are of course right, this will need inspecting anyway ... |
232f516
to
0364acc
Compare
Could you by any chance take a look at the latest commit? I have refactored the registration process such that clients are required to subclass
From a high-level, this this look good to you? |
2cf0b28
to
d8e4ec7
Compare
The dict returned by `get_metadata` was keyed by the *truncated* metadata key, and not the original one. As the metadata widget uses the original keys to read out the data, nothing was displayed if long keys are used in the config.
I did not replace the link with one to `metadata.rst` as this lead to a weird error. I also do not think that this link is super relevant.
92975bc
to
f62ede3
Compare
If no metadata plugin has been specified, the default `metadata` plugins loads one of `metadata_pyexiv` or `metadata_piexif` (depending on the installed backend). If a specific backend is configured, they it is ensured that `metadata` does not interfere. This is achieved by deferring the loading of the `metadata` plugin to the end of all plugins. At that point `metadata` can check if another metadata plugin has been loaded, and if so, do nothing.
f62ede3
to
fb66610
Compare
I have rebased this branch for master, and updated and restructured the TODOs in the PRs description. The restructuring should make it better visible what has been done in this PR and what is left to do. This should (hopefully) facility the review of this PR [1] 😇 In addition, I have added a proposition (fb66610) to the last outstanding issue: [1] Since you have been a bit more active last week, I had the hope that you may have a look at (and review 🫣) this PR when I get it up to date again. But no pressure - take the time you need 😬 |
So, I was finally able to give this another try. Excellent work, I believe almost all issues are solved and this is nearly ready to be merged. I tried to tackle some of the last bits in the
Final remaining part would be the documentation points you mentioned. |
User plugins are now loaded before app plugins, and not overridden. This allows metadata (and any other app plugins) to be loaded later and access any user-specific information. In this case, the user can deactivate auto-loading by passing metadata = none in the plugins section of the config.
Thank you very much for taking time to review this PR! Your changes in the I have updated the docs. Let me know if there is anything to improve. Otherwise, I am done with this PR 😃 |
Thanks a bunch for the documentation, I will either just merge or push changes here directly once I get to it, no more need for another iteration I hope 🎉 CI: would you mind removing that one commit again? This currently doesn't work unfortunately, thus the "please ignore this for now" 😉 |
Also make them Title Case, as in other pasts of the docs
fe42760
to
816dc32
Compare
Oh, I though I should ignore that it is broken 🙈 I have remove it Yeah, if there are not major things, feel free to correct everything yourself directly. |
Merged - so ... party? 😄 🎉 |
Well, that is simply amazing🎉 Metadata support has been a burden for such a long time, and how we have finally sorted it out for once and for all [1] [1] Better do not quote me on this 🫣 😆 |
Desperate attempt to get metadata to work nr 148 😋
We have had so many troubles to get metadata support and none of the available solutions seemed perfect. To quickly summarize to issues we have had:
So I thought that is is probably the best idea to move the "dirty code" out to plugin space. More precisely, my idea was to remove all metadata related code which is fixed to a certain package, and instead add an interface which allows to load plugins which add metadata support. I would create
onetwo "official"/internal plugin for metadata support based on piexif and pyexiv2, and then anyone is free to implement metadata plugins using whatever method one likes.This PR is very WIP.Almost complete. Any feedback is very welcomeUpdate: I will maintain the TODOs in order to keep the overview...
TODOs
Main Implementation
get_metadata
,get_keys
,copy_metadata
, andget_date_time
Metadata Plugins
piexif
backendpyexiv2
backendConfiguration
metadata
Handle case where there is no metadata support
MetadataWidget
should not be loadedplugins_loaded
signal (thanks @karlch!)Testing
CI
Docs
Misc
Deferred for another PR
Internal metadata keys (ref Internal metadata keys #325)
Display of metadata plugin (backend) version in
:version/--version
imutils.metadata.get_registrations
) has been addedDeprecate default metadata support?
Interface for writing metadata